import { Modal, Toast } from 'antd-mobile'
import { Dispatch, SetStateAction } from 'react'

// modal 点击各种关闭按钮时
export function onModalCancel() {
  // setModalVisible: Dispatch<SetStateAction<boolean>>,
  // formApi: FormApi<any> | undefined,
  // initForm: any
  // // 判断表单是否修改
  // let flag = false
  // for (const key in formApi?.getValues()) {
  //   if (
  //     JSON.stringify(initForm[key]) !==
  //     JSON.stringify(formApi?.getValues()[key])
  //   ) {
  //     flag = true
  //     break
  //   }
  // }
  // // 如果没有修改，则关闭 modal
  // if (!flag) {
  //   setModalVisible(false)
  //   return
  // }
  // // 否则进行提示
  // execConfirm(
  //   async () => {
  //     setModalVisible(false)
  //   },
  //   undefined,
  //   '表单数据已被修改，确定关闭吗？'
  // )
}

// 格式化数字：加逗号
export function toThousands(val?: string | number) {
  let num = (val || 0).toString(),
    result = ''
  while (num.length > 3) {
    result = ',' + num.slice(-3) + result
    num = num.slice(0, num.length - 3)
  }
  if (num) {
    result = num + result
  }
  return result
}

let timer: NodeJS.Timeout
// 全局的防抖
export function debounce(fun: () => void, time = 300) {
  clearTimeout(timer) // 清除定时器
  timer = setTimeout(fun, time)
}

interface IFlatTree {
  children?: any[]
}

// 扁平化树结构，备注：hasParentFlag：是否需要父节点，checkFun：return true的节点，才需要添加
export function flatTree<T extends IFlatTree>(
  data?: T[],
  hasParentFlag: boolean = true,
  checkFun?: (item: T) => boolean
) {
  let resList: T[] = []
  if (!data) {
    return resList
  }
  data.forEach((item) => {
    let flag = true
    if (checkFun) {
      flag = checkFun(item) // 过滤不要的节点
    }
    if (flag) {
      const hasChildren = item.children && item.children.length
      if (hasChildren) {
        if (hasParentFlag) {
          resList.push(JSON.parse(JSON.stringify({ ...item, children: null }))) // 添加到返回值里
        }
        resList = resList.concat(
          flatTree(item.children, hasParentFlag, checkFun)
        )
      } else {
        resList.push(JSON.parse(JSON.stringify({ ...item, children: null }))) // 添加到返回值里
      }
    }
  })
  return resList
}

// 获取树结构，所有 有子节点的 id集合
export function getHasChildrenIdListForTree(data: any[]) {
  let resList: string[] = []
  data.forEach((item) => {
    if (item.children && item.children.length) {
      resList.push(item.id)
      resList = resList.concat(getHasChildrenIdListForTree(item.children))
    }
  })
  return resList
}

interface IListToTree {
  [x: string]: any
}

// list 转 tree 结构，比原始的递归快
// childrenFlag：true：children始终为 [] false：children为空时，children = ''
export function listToTree<T extends IListToTree>(
  list: T[],
  childrenFlag: boolean = true,
  pid: string = '0',
  childrenName: string = 'children'
) {
  const resList: T[] = [] // 本方法返回值
  const obj: any = {} // 格式：{ id: {...item} }

  list.forEach((item: any) => {
    if (obj[item.id]) {
      // 如果存在 当前元素
      if (obj[item.id][childrenName] && obj[item.id][childrenName].length) {
        // 如果 存在的元素，有 children，并且不为空
        delete item[childrenName] // 删除当前元素的 children属性，目的：防止 obj里面元素的 children属性被 覆盖
      }
      item = { ...obj[item.id], ...item }
    } else {
      // 如果不存在 当前元素
      if (!item[childrenName]) {
        // 如果 item不存在 children
        if (childrenFlag) {
          item[childrenName] = []
        } else {
          item[childrenName] = ''
        }
      }
      obj[item.id] = item // 赋值到 obj里面
    }

    if (item.parentId === pid) {
      resList.push(item) // 添加到返回值里
      return
    }

    if (obj[item.parentId]) {
      // 如果存在 父级元素
      if (obj[item.parentId][childrenName]) {
        obj[item.parentId][childrenName].push(item)
      } else {
        obj[item.parentId][childrenName] = [item]
      }
    } else {
      // 如果不存在 父级元素
      obj[item.parentId] = { [childrenName]: [item] }
    }
  })

  return resList
}

interface ICalcOrderNoForm {
  orderNo?: number
  [x: string]: any
}

interface ICalcOrderNoRecord {
  children?: ICalcOrderNoForm[]
}

// 计算 orderNo
export function calcOrderNo<
  T extends ICalcOrderNoForm,
  P extends ICalcOrderNoRecord
>(
  form: T,
  record: P,
  calcFun?: ({
    item,
    form,
    record,
  }: {
    item: ICalcOrderNoForm
    form: T
    record: P
  }) => void
) {
  if (record.children && record.children.length) {
    let orderNo = Number(record.children[0].orderNo) - 10 // 默认为第一个子节点元素减去 10
    form.orderNo = orderNo < 0 ? 0 : orderNo

    // 如果存在子节点，那么取最小的 orderNo - 10，如果 减完之后小于零，则为 0
    record.children.forEach((item) => {
      if (calcFun) {
        calcFun({ item, form, record }) // 计算其他属性
      }
      // orderNo <= 0 的不进行计算
      if (
        item.orderNo &&
        form.orderNo &&
        item.orderNo > 0 &&
        item.orderNo <= form.orderNo
      ) {
        orderNo = item.orderNo - 10
        form.orderNo = orderNo < 0 ? 0 : orderNo
      }
    })
  } else {
    if (form.orderNo === undefined || form.orderNo === null) {
      form.orderNo = 10000 // 默认为 10000
    }
  }
}

// 下载文件：需要这样请求 $http({responseType: 'blob'})
// 使用：download(res.data, res.headers['content-disposition'])
export function download(
  res: any,
  fileName: string = new Date().getTime() + '.xlsx'
) {
  if (!res) {
    throw new Error('download 方法的res参数不能为空')
  }
  const blob = new Blob([res])

  fileName = fileName.includes('filename=')
    ? decodeURIComponent(fileName.split('filename=')[1])
    : fileName

  const link = document.createElement('a')
  link.download = fileName
  link.style.display = 'none'
  link.href = URL.createObjectURL(blob)
  document.body.appendChild(link)
  link.click()
  URL.revokeObjectURL(link.href) // 释放URL 对象
  document.body.removeChild(link)
}

// 处理后台返回的 ip所处区域
export function handlerRegion(region: string) {
  if (!region) return region
  return region
    .split('|')
    .filter((item) => item !== '0')
    .join(' ')
}

// 获取随机字符串
export function randomString(length: number = 6) {
  const BASE_CHAR_NUMBER = 'abcdefghijklmnopqrstuvwxyz0123456789'
  let resStr = ''
  for (let index = 0; index < length; index++) {
    resStr += BASE_CHAR_NUMBER.charAt(Math.floor(Math.random() * 36))
  }
  return resStr
}

// 根据list和 value，获取字典的 name值
export function getNameByValueAndDictList(
  // dictList: OptionProps[],
  value: number | string,
  resField: string = 'label',
  valField: string = 'value'
) {
  // let res: number | string | undefined = undefined
  // dictList.some((item) => {
  //   if (item[valField] === value) {
  //     res = item[resField]
  //     return true // 结束当前循环
  //   }
  // })
  // return res
}

// 注意：【confirmFun】和【cancelFun】，如果是 http请求，则需要 return http 请求，如果不是 Promise，则在方法前面加 async，即可
export function execConfirm(
  confirmFun: () => Promise<void>,
  cancelFun?: () => Promise<void>,
  msg?: string
) {
  Modal.confirm({
    title: '提示',
    content: msg || '确定执行操作？',
    onConfirm: () => {
      return new Promise(async (resolve, reject) => {
        if (confirmFun) {
          return await confirmFun()
            .then(() => resolve())
            .catch(() => resolve())
        }
        return resolve() // 关闭 confirm弹窗
      })
    },
    onCancel() {
      return new Promise(async (resolve, reject) => {
        if (cancelFun) {
          return await cancelFun()
            .then(() => resolve())
            .catch(() => resolve())
        }
        return resolve() // 关闭 confirm弹窗
      })
    },
  })
}

// 下划线转换驼峰
export function toHump(name: string) {
  return name.replace(/\_(\w)/g, function (all, letter) {
    return letter.toUpperCase()
  })
}

// 通用的错误弹窗
export function ToastError(
  content: string,
  duration: number = 4,
  maskClickable: boolean = true
) {
  return ToastInfo(content || 'Error', duration, 'fail', maskClickable)
}

// 通用的正确弹窗
export function ToastSuccess(
  content: string,
  duration: number = 4,
  maskClickable: boolean = true
) {
  return ToastInfo(content, duration, 'success', maskClickable)
}

// 通用的信息弹窗，备注：官网提示：同一时间只允许弹出一个轻提示，新出现的 Toast 会将之前正在显示中的 Toast 挤掉。
export function ToastInfo(
  content: string,
  duration: number = 3,
  icon?: 'success' | 'fail' | 'loading' | React.ReactNode,
  maskClickable: boolean = false
) {
  return Toast.show({
    content,
    duration: duration * 1000,
    icon,
    maskClickable,
  })
}
